[XEN] Track high-water-mark of p2m map
authorTim Deegan <Tim.Deegan@xensource.com>
Wed, 15 Nov 2006 14:36:10 +0000 (14:36 +0000)
committerTim Deegan <Tim.Deegan@xensource.com>
Wed, 15 Nov 2006 14:36:10 +0000 (14:36 +0000)
and so avoid some unnecessary __copy_from_user faults.
Also tidy the p2m functions generally.
Signed-off-by: Tim Deegan <Tim.Deegan@xensource.com>
xen/arch/x86/mm/shadow/common.c
xen/arch/x86/mm/shadow/types.h
xen/include/asm-x86/domain.h
xen/include/asm-x86/hvm/io.h
xen/include/asm-x86/mm.h
xen/include/asm-x86/shadow.h

index 7461882a38a370519a8d4b7e4c17050ea3e09687..500375545c54b9c61fd727060a683bb48b351ae7 100644 (file)
@@ -1047,6 +1047,10 @@ shadow_set_p2m_entry(struct domain *d, unsigned long gfn, mfn_t mfn)
     else
         *p2m_entry = l1e_empty();
 
+    /* Track the highest gfn for which we have ever had a valid mapping */
+    if ( valid_mfn(mfn) && (gfn > d->arch.max_mapped_pfn) ) 
+        d->arch.max_mapped_pfn = gfn;
+
     /* The P2M can be shadowed: keep the shadows synced */
     if ( d->vcpu[0] != NULL )
         (void)__shadow_validate_guest_entry(
@@ -1142,12 +1146,9 @@ sh_gfn_to_mfn_foreign(struct domain *d, unsigned long gpfn)
     mfn = pagetable_get_mfn(d->arch.phys_table);
 
 
-#if CONFIG_PAGING_LEVELS > 2
-    if ( gpfn >= (RO_MPT_VIRT_END-RO_MPT_VIRT_START) / sizeof(l1_pgentry_t) ) 
-        /* This pfn is higher than the p2m map can hold */
+    if ( gpfn > d->arch.max_mapped_pfn ) 
+        /* This pfn is higher than the highest the p2m map currently holds */
         return _mfn(INVALID_MFN);
-#endif
-
 
 #if CONFIG_PAGING_LEVELS >= 4
     { 
@@ -3333,13 +3334,14 @@ void shadow_audit_p2m(struct domain *d)
             set_gpfn_from_mfn(mfn, INVALID_M2P_ENTRY);
         }
 
-        if ( test_linear )
+        if ( test_linear && (gfn <= d->arch.max_mapped_pfn) )
         {
-            lp2mfn = get_mfn_from_gpfn(gfn);
-            if ( lp2mfn != mfn_x(p2mfn) )
+            lp2mfn = gfn_to_mfn_current(gfn);
+            if ( mfn_x(lp2mfn) != mfn_x(p2mfn) )
             {
                 SHADOW_PRINTK("linear mismatch gfn %#lx -> mfn %#lx "
-                               "(!= mfn %#lx)\n", gfn, lp2mfn, p2mfn);
+                              "(!= mfn %#lx)\n", gfn, 
+                              mfn_x(lp2mfn), mfn_x(p2mfn));
             }
         }
 
index 2dd2908d699f621d2f9797613170a2b10b76c6ff..698283ea92bf7faefd9dbf2b76f5642a3209c8fc 100644 (file)
@@ -416,9 +416,7 @@ vcpu_gfn_to_mfn(struct vcpu *v, gfn_t gfn)
 {
     if ( !shadow_vcpu_mode_translate(v) )
         return _mfn(gfn_x(gfn));
-    if ( likely(current->domain == v->domain) )
-        return _mfn(get_mfn_from_gpfn(gfn_x(gfn)));
-    return sh_gfn_to_mfn_foreign(v->domain, gfn_x(gfn));
+    return sh_gfn_to_mfn(v->domain, gfn_x(gfn));
 }
 
 static inline gfn_t
index 71fd4dcd3bf36b787a4feb6f5e2d2fc310f8ab68..89535b5810e38f034318d51474243791a1bd9055 100644 (file)
@@ -111,6 +111,8 @@ struct arch_domain
 
     /* Shadow translated domain: P2M mapping */
     pagetable_t phys_table;
+    /* Highest guest frame that's ever been mapped in the p2m */
+    unsigned long max_mapped_pfn;
 
 } __cacheline_aligned;
 
index b9349380067ae41411ad1260d10a0db69c2398db..55ac4b5c3c2de038412f026e66147e7309672c70 100644 (file)
@@ -151,8 +151,5 @@ extern void pic_irq_request(void *data, int level);
 extern int cpu_get_interrupt(struct vcpu *v, int *type);
 extern int cpu_has_pending_irq(struct vcpu *v);
 
-// XXX - think about this, maybe use bit 30 of the mfn to signify an MMIO frame.
-#define mmio_space(gpa) (!VALID_MFN(get_mfn_from_gpfn((gpa) >> PAGE_SHIFT)))
-
 #endif /* __ASM_X86_HVM_IO_H__ */
 
index cb7dfd7ebbebf50cba654693fb77463397860f6d..d8cffdeb4a8dda48d82d6f470f259db74f974b03 100644 (file)
@@ -304,37 +304,9 @@ int check_descriptor(struct desc_struct *d);
 
 #define gmfn_to_mfn(_d, gpfn)  mfn_x(sh_gfn_to_mfn(_d, gpfn))
 
-
-/*
- * The phys_to_machine_mapping is the reversed mapping of MPT for full
- * virtualization.  It is only used by shadow_mode_translate()==true
- * guests, so we steal the address space that would have normally
- * been used by the read-only MPT map.
- */
-#define phys_to_machine_mapping ((l1_pgentry_t *)RO_MPT_VIRT_START)
 #define INVALID_MFN             (~0UL)
 #define VALID_MFN(_mfn)         (!((_mfn) & (1U<<31)))
 
-static inline unsigned long get_mfn_from_gpfn(unsigned long pfn)
-{
-    l1_pgentry_t l1e = l1e_empty();
-    int ret;
-
-#if CONFIG_PAGING_LEVELS > 2
-    if ( pfn >= (RO_MPT_VIRT_END - RO_MPT_VIRT_START) / sizeof(l1_pgentry_t) ) 
-        /* This pfn is higher than the p2m map can hold */
-        return INVALID_MFN;
-#endif
-
-    ret = __copy_from_user(&l1e,
-                               &phys_to_machine_mapping[pfn],
-                               sizeof(l1e));
-
-    if ( (ret == 0) && (l1e_get_flags(l1e) & _PAGE_PRESENT) )
-        return l1e_get_pfn(l1e);
-
-    return INVALID_MFN;
-}
 
 #ifdef MEMORY_GUARD
 void memguard_init(void);
index dfc1122cb54f9a60580255eed99904a2fc80ddc1..af9abff3f46cf58353e00134d88b014601e36fe4 100644 (file)
@@ -663,12 +663,40 @@ struct shadow_walk_cache {
 
 
 /**************************************************************************/
-/* Guest physmap (p2m) support */
+/* Guest physmap (p2m) support 
+ *
+ * The phys_to_machine_mapping is the reversed mapping of MPT for full
+ * virtualization.  It is only used by shadow_mode_translate()==true
+ * guests, so we steal the address space that would have normally
+ * been used by the read-only MPT map.
+ */
 
-/* Walk another domain's P2M table, mapping pages as we go */
-extern mfn_t
-sh_gfn_to_mfn_foreign(struct domain *d, unsigned long gpfn);
+#define phys_to_machine_mapping ((l1_pgentry_t *)RO_MPT_VIRT_START)
+
+/* Read the current domain's P2M table. */
+static inline mfn_t sh_gfn_to_mfn_current(unsigned long gfn)
+{
+    l1_pgentry_t l1e = l1e_empty();
+    int ret;
+
+    if ( gfn > current->domain->arch.max_mapped_pfn )
+        return _mfn(INVALID_MFN);
+
+    /* Don't read off the end of the p2m table */
+    ASSERT(gfn < (RO_MPT_VIRT_END - RO_MPT_VIRT_START) / sizeof(l1_pgentry_t));
+
+    ret = __copy_from_user(&l1e,
+                           &phys_to_machine_mapping[gfn],
+                           sizeof(l1e));
+
+    if ( (ret == 0) && (l1e_get_flags(l1e) & _PAGE_PRESENT) )
+        return _mfn(l1e_get_pfn(l1e));
+
+    return _mfn(INVALID_MFN);
+}
 
+/* Walk another domain's P2M table, mapping pages as we go */
+extern mfn_t sh_gfn_to_mfn_foreign(struct domain *d, unsigned long gpfn);
 
 /* General conversion function from gfn to mfn */
 static inline mfn_t
@@ -676,12 +704,19 @@ sh_gfn_to_mfn(struct domain *d, unsigned long gfn)
 {
     if ( !shadow_mode_translate(d) )
         return _mfn(gfn);
-    else if ( likely(current->domain == d) )
-        return _mfn(get_mfn_from_gpfn(gfn));
-    else
+    if ( likely(current->domain == d) )
+        return sh_gfn_to_mfn_current(gfn);
+    else 
         return sh_gfn_to_mfn_foreign(d, gfn);
 }
 
+/* Compatibility function for HVM code */
+static inline unsigned long get_mfn_from_gpfn(unsigned long pfn)
+{
+    return mfn_x(sh_gfn_to_mfn_current(pfn));
+}
+
+/* General conversion function from mfn to gfn */
 static inline unsigned long
 sh_mfn_to_gfn(struct domain *d, mfn_t mfn)
 {
@@ -691,6 +726,14 @@ sh_mfn_to_gfn(struct domain *d, mfn_t mfn)
         return mfn_x(mfn);
 }
 
+/* Is this guest address an mmio one? (i.e. not defined in p2m map) */
+static inline int
+mmio_space(paddr_t gpa)
+{
+    unsigned long gfn = gpa >> PAGE_SHIFT;    
+    return !VALID_MFN(mfn_x(sh_gfn_to_mfn_current(gfn)));
+}
+
 static inline l1_pgentry_t
 gl1e_to_ml1e(struct domain *d, l1_pgentry_t l1e)
 {